package aio;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.xml.crypto.Data;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.Date;
import java.util.concurrent.CountDownLatch;

/**
 * Created by GanJc on 2015/11/15.
 */
public class TimeServer {

    private static final Logger logger = LoggerFactory.getLogger(TimeServer.class);

    public static void main(String[] args) {
        int port = 8888 ;
        new Thread(new AsyncTimeServerHandler(port),"async-time-server").start();
    }

    private static class AsyncTimeServerHandler implements Runnable{

        private int port ;

        private CountDownLatch countDownLatch ;

        private AsynchronousServerSocketChannel asc ;

        public AsyncTimeServerHandler(int port) {
            this.port = port;
            countDownLatch = new CountDownLatch(1);
            try {
                asc = AsynchronousServerSocketChannel.open();
                asc.bind(new InetSocketAddress(port));
                logger.info("asc time server start at port : {}" ,port);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void run() {
            doAccept();
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        private void doAccept() {
            asc.accept(this, new CompletionHandler<AsynchronousSocketChannel, AsyncTimeServerHandler>() {
                @Override
                public void completed(AsynchronousSocketChannel result, AsyncTimeServerHandler attachment) {
                    attachment.asc.accept(attachment,this);
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                    result.read(byteBuffer, byteBuffer, new ReadCompletionHandle(result));
                }

                @Override
                public void failed(Throwable exc, AsyncTimeServerHandler attachment) {
                    exc.printStackTrace();
                    attachment.countDownLatch.countDown();
                }
            });

        }
    }

    private static class ReadCompletionHandle implements CompletionHandler<Integer,ByteBuffer>{

        private AsynchronousSocketChannel channel ;

        public ReadCompletionHandle(AsynchronousSocketChannel channel) {
            this.channel = channel;
        }

        @Override
        public void completed(Integer result, ByteBuffer attachment) {
                attachment.flip();
                byte[] bytes = new byte[attachment.remaining()];
                attachment.get(bytes);
                try {
                    String body = new String(bytes,"utf-8");
                    logger.info("收到的请求是:{}",body);
                    String resp ;
                    if("TIME".equals(body)){
                        resp = "现在时间是:" + new Date();
                    }else {
                        resp = "非法请求" ;
                    }
                    byte[] respBytes = resp.getBytes();
                    ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
                    writeBuffer.put(respBytes);
                    writeBuffer.flip();
                    channel.write(writeBuffer, writeBuffer, new CompletionHandler<Integer, ByteBuffer>() {
                        @Override
                        public void completed(Integer result, ByteBuffer attachment) {
                            if (attachment.hasRemaining()){
                                channel.write(attachment,attachment,this);
                            }
                        }

                        @Override
                        public void failed(Throwable exc, ByteBuffer attachment) {
                            try {
                                channel.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
        }

        @Override
        public void failed(Throwable exc, ByteBuffer attachment) {
            exc.printStackTrace();
            try {
                channel.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}
